package service

import (
	"blog-server/global"
	"blog-server/models"
	"blog-server/models/views"
	"blog-server/utils"
	"blog-server/utils/msg"
	"github.com/sirupsen/logrus"
	"io/ioutil"
	"strconv"
	"strings"
	"time"
	"xorm.io/xorm"
)

type ArticleService struct{}

func NewArticleService() *ArticleService {
	return &ArticleService{}
}

// ArticleAdminList 后台文章列表
func (article *ArticleService) ArticleAdminList(param views.ArticleListVo) (*msg.DataPage, error) {
	var dataList []views.AdminArticleList

	condition := func(session *xorm.Session) *xorm.Session {
		session = session.Join("left", []string{"blog_art_cate", "b"}, "a.id = b.art_id")
		session = session.Where("a.can_view = true")
		if param.Title != "" {
			session = session.Where("a.title = ?", param.Title)
		}
		if param.Title != "" {
			session = session.Where("a.title = ?", param.Title)
		}
		if param.StartTime != "" && param.EndTime == "" {
			session = session.Where("a.create_time >= ?", param.StartTime)
		}
		if param.EndTime != "" && param.StartTime == "" {
			session = session.Where("a.create_time <= ?", param.EndTime)
		}
		if param.StartTime != "" && param.EndTime != "" {
			session = session.Where("a.create_time between ? and ?", param.StartTime, param.EndTime)
		}
		return session
	}

	if param.Page <= 0 {
		param.Page = 1
	}
	if param.Limit <= 0 {
		param.Limit = 10
	}

	session := global.Engine.Table(&models.Article{}).Alias("a").Select("a.id, a.title, a.synopsis, a.markdown, a.create_time, a.art_draft, a.art_overhead, a.tags, group_concat(b.cate_id Separator ',') as cate_list")
	err1 := condition(session).GroupBy("a.id").Desc("a.create_time").Limit(param.Limit, (param.Page-1)*param.Limit).Find(&dataList)

	if err1 != nil {
		logrus.Error("后台文章列表:查询数据列表失败", err1.Error())
		return &msg.DataPage{}, msg.NewSysError(err1.Error())
	}

	countSession := global.Engine.Table(&models.Article{}).Alias("a")
	count, err2 := condition(countSession).Count()
	if err2 != nil {
		return &msg.DataPage{}, msg.NewSysError(err2.Error())
	}
	return msg.NewDataPage(dataList, count, param.Page, param.Limit), nil
}

// ArticleSelectPages 搜索文章数据
func (article *ArticleService) ArticleSelectPages(param *views.HomeArticlePageVo) (*msg.DataPage, error) {
	var dataList []views.ArticleHomeRespVo
	var categoryList []views.CategoryList
	cateIdMap := make(map[int]views.CategoryList, 0)
	condition := func(session *xorm.Session) *xorm.Session {
		session = session.Join("left", []string{"blog_art_cate", "b"}, "a.id = b.art_id")
		session = session.Join("right", []string{"blog_category", "c"}, "b.cate_id = c.id")
		session = session.Where("a.can_view = true")
		if param.CategoryId != 0 {
			session = session.Where("b.cate_id = ?", param.CategoryId)
		}
		if param.Tags != "" {
			session = session.Where("find_in_set(?, a.tags)", param.Tags)
		}
		if param.Time != "" {
			session = session.Where("DATE_FORMAT(a.create_time, '%Y-%m-%d') = ?", param.Time)
		}
		session = session.GroupBy("a.id")
		return session
	}

	// 获取分类信息
	err := global.Engine.Table("blog_category").Select("id, title").Find(&categoryList)
	if err != nil {
		return &msg.DataPage{}, msg.NewSysError(err.Error())
	}
	for idx, item := range categoryList {
		cateIdMap[idx] = item
	}

	if param.Page <= 0 {
		param.Page = 1
	}
	if param.Size <= 0 {
		param.Size = 10
	}
	// 获取数据
	session := global.Engine.Table("blog_article").Alias("a").Select("a.id, a.title, a.synopsis, a.create_time, a.art_length, a.integral_num, a.reads_num, a.reviews_num, a.art_overhead, a.praise_num, a.tags, group_concat(c.id) as cate_list")
	err = condition(session).Desc("a.art_overhead").Asc("a.create_time").Limit(param.Size, (param.Page-1)*param.Size).Find(&dataList)
	if err != nil {
		return &msg.DataPage{}, msg.NewSysError(err.Error())
	}
	if len(dataList) == 0 {
		dataList = []views.ArticleHomeRespVo{}
	} else {
		for idx, key := range dataList {
			categoryList := make([]views.CategoryList, 0)
			if key.CateList != "" {
				cates := strings.Split(key.CateList, ",")
				for _, innerItem := range cates {
					cateId, _ := strconv.Atoi(innerItem)
					categoryList = append(categoryList, cateIdMap[cateId])
				}
			}
			key.CategoryList = categoryList
			dataList[idx] = key
		}
	}

	// 获取数量
	countSession := global.Engine.Table("blog_article").Alias("a")
	count, err1 := condition(countSession).Count(&models.Article{})
	if err1 != nil {
		return &msg.DataPage{}, msg.NewSysError(err1.Error())
	}

	return msg.NewDataPage(dataList, count, param.Page, param.Size), nil
}

// ArticleDeleteByIds 删除文章数据
func (article *ArticleService) ArticleDeleteByIds(param []string) error {
	tx := global.Engine.NewSession()
	defer tx.Close()
	err := tx.Begin()
	if err != nil {
		err := tx.Rollback()
		if err != nil {
			return err
		}
		return msg.NewSysError("删除数据失败")
	}

	_, err = tx.Table(models.Article{}).In("id", param).Update(map[string]interface{}{"can_view": false, "update_time": time.Now()})
	if err != nil {
		err := tx.Rollback()
		if err != nil {
			return err
		}
		logrus.Fatalf("批量删除数据失败：%s\n", err.Error())
		return msg.NewSysError("删除数据失败")
	}
	return tx.Commit()
}

// ArticleOverHeadFlag 设置文章顶置状态
func (article *ArticleService) ArticleOverHeadFlag(id string, flag bool) error {
	session := global.Engine.NewSession()
	defer session.Close()
	err := session.Begin()
	if err != nil {
		return err
	}
	_, err = session.Where("id = ?", id).Update(map[string]interface{}{"art_overhead": flag, "update_create": time.Now()})
	if err != nil {
		session.Rollback()
		return msg.NewSysError("设置文章顶置状态失败")
	}
	return session.Commit()
}

// ArticleTagsAll 文章标签列表
func (article *ArticleService) ArticleTagsAll() ([]string, error) {
	var data []models.Article
	session := global.Engine.NewSession()
	defer session.Close()
	err := session.Begin()
	if err != nil {
		return nil, err
	}
	err = session.Select("tags").Where("can_view = true and art_draft = false").Find(&data)
	if err != nil {
		return nil, msg.NewSysError(err.Error())
	}
	err = session.Commit()
	if err != nil {
		return nil, err
	}
	if len(data) == 0 {
		return make([]string, 0), nil
	}
	return duplicateRemoval(data), nil
}

// duplicateRemoval 数组去重
func duplicateRemoval(value []models.Article) []string {
	initArr := make([]string, 0)
	sentence := make(map[string]struct{}, 0)
	for _, item := range value {
		split := strings.Split(item.Tags, ",")
		for j := 0; j < len(split); j++ {
			if _, ok := sentence[split[j]]; !ok {
				sentence[split[j]] = struct{}{}
				initArr = append(initArr, split[j])
			}
		}
	}
	return initArr
}

// ArticleDetail 文章详情
func (article *ArticleService) ArticleDetail(id int) (views.ArticleDetailVo, error) {
	var articleModel models.Article
	var categoryList []views.CategoryList
	var artCate []models.ArtCate
	var result views.ArticleDetailVo
	_, err := global.Engine.ID(id).Get(&articleModel)
	if err != nil || articleModel.ArtDraft || !articleModel.CanView {
		return views.ArticleDetailVo{}, err
	}

	utils.StructCopy(articleModel, &result)
	if articleModel.Tags != "" {
		tags := strings.Split(articleModel.Tags, ",")
		result.Tags = tags
	}
	err = global.Engine.Where("art_id = ?", id).Select("cate_id").Find(&artCate)
	if err != nil || len(artCate) <= 0 {
		return views.ArticleDetailVo{}, msg.NewSysError("文章分类获取失败")
	}
	cateIds := make([]int, 0)
	for _, item := range artCate {
		cateIds = append(cateIds, item.CateId)
	}

	err = global.Engine.Table("blog_category").In("id", cateIds).Where("can_view = true").Select("id, title").Find(&categoryList)
	if err != nil {
		return views.ArticleDetailVo{}, msg.NewSysError("获取分类失败")
	}
	result.CategoryList = categoryList
	return result, nil
}

// ArticleUploadByFile 文章上传
func (article *ArticleService) ArticleUploadByFile(params views.AdminArticleUploadVo) (bool, error) {
	articleEntity := new(models.Article)
	articleEntity.ArtOverhead = params.ArtOverhead
	articleEntity.ArtDraft = params.ArtDraft
	articleEntity.Title = params.Title
	articleEntity.Synopsis = params.Synopsis
	articleEntity.Tags = params.Tags
	articleEntity.CanView = true
	articleEntity.CreateTime = time.Now()
	articleEntity.UpdateTime = time.Now()
	// 获取文章内容
	open, err := params.File.Open()
	if err != nil {
		return false, err
	}
	content, err := ioutil.ReadAll(open)
	if err != nil {
		return false, msg.NewSysError("获取文件内容失败")
	}
	articleEntity.Markdown = string(content)
	_, err = global.Engine.InsertOne(articleEntity)
	if err != nil {
		return false, err
	}
	// 设置文章和分类关系
	artCate := &models.ArtCate{
		CateId: params.CategoryId,
		ArtId:  articleEntity.Id,
	}
	_, err = global.Engine.Insert(artCate)
	if err != nil {
		return false, msg.NewSysError("保存文章分类关系数据失败")
	}
	return true, nil
}

// ArticleArchive 获取归档文章内容
func (article *ArticleService) ArticleArchive(year string) (*views.ArticleArchiveVo, error) {
	result := new(views.ArticleArchiveVo)
	var archiveItem []views.ArchiveItemVo
	err := global.Engine.Table(&models.Article{}).Where("DATE_FORMAT(create_time, '%Y') = ?", year).Desc("create_time").Find(&archiveItem)
	if err != nil {
		return &views.ArticleArchiveVo{}, err
	}
	result.List = archiveItem
	result.Year = year
	count, err := global.Engine.Table(&models.Article{}).Where("DATE_FORMAT(create_time, '%Y') = ?", year).Count()
	if err != nil {
		return &views.ArticleArchiveVo{}, err
	}
	result.Total = count
	return result, nil
}

// ArticleContent 获取文章内容
func (article *ArticleService) ArticleContent(id string) string {
	var temp models.Article
	_, err := global.Engine.Table(&models.Article{}).ID(id).Select("markdown").Get(&temp)
	if err != nil {
		logrus.Error("文章内容不存在", err.Error())
		return ""
	} else {
		return temp.Markdown
	}
}
